package com.qf.config;

import com.alibaba.fastjson.JSONObject;
import com.google.common.util.concurrent.RateLimiter;
import com.qf.pojo.respVo.BaseResp;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;


/**
 * 1.aop的业务使用：
 *  1.1 日志记录
 *  1.2 事务
 *  1.3 扫描自定义注解，进行业务增强
 */
@Aspect
@Component
public class AccessLimitAop {

    @Autowired
    private HttpServletResponse response;
    //声明令牌桶，每秒放行20个请求
    private RateLimiter rateLimiter=RateLimiter.create(1.0);


   private static  final   Logger logger= LoggerFactory.getLogger(AccessLimitAop.class);

    //1.定义对于哪些方法进行增强。声明切点。我们现在需要的是扫描自定义注解
    //excution 定义切点对于哪些方法进行增强
    @Pointcut(value = "@annotation(com.qf.annoration.AccessLimit)")
    public void pointcut(){}

    //我们对接口进行增强方法，拦截到加了自定义注解的接口，首先来执行增强方法
    //判断当前的请求是否可以放行，是否可以从令牌桶中获取到令牌

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws IOException {
        //判断是否该请求获取到了令牌
    logger.debug("进入了令牌桶的判断,看看是否放行");
        //尝试从令牌中获取令牌
        boolean b = rateLimiter.tryAcquire();
        String name = Thread.currentThread().getName();
        Object proceed=null;
        try {
        if (b){
        logger.debug("===========获取到令牌继续执行业务逻辑==========当前线程为:{}"+name);

                proceed=point.proceed();
                return proceed;
            } else {
            logger.debug("===获取令牌失败！=="+name);
            //没有获取到令牌需要返回 ，不再继续请求
            String result=    JSONObject.toJSONString(new BaseResp().Fail(0,"请求过多"));
            //通过httpservletResponse进行返回
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            //使用response进行返回数据
            ServletOutputStream outputStream = response.getOutputStream();
            //将错误结果进行返回操作
            outputStream.write(result.getBytes(StandardCharsets.UTF_8));
            outputStream.close();
        }
        }catch (Throwable e) {
            throw new RuntimeException(e);
        }
        return proceed;
    }
}
